home *** CD-ROM | disk | FTP | other *** search
/ SPACE 1 / SPACE - Library 1 - Volume 1.iso / program / 441 / dlibs12 / scanf.c < prev    next >
C/C++ Source or Header  |  1990-11-23  |  8KB  |  421 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3.  
  4. extern    char    _numstr[];
  5.  
  6. /* #define    skip()    do{c=(*get)(ip); if (c<1) goto done;}while(isspace(c))*/
  7.  
  8. #define    skip()    while(isspace(c)) { if ((c=(*get)(ip))<1) goto done; }
  9.  
  10. #if FLOATS
  11. /* fp scan actions */
  12. #define F_NADA    0    /* just change state */
  13. #define F_SIGN    1    /* set sign */
  14. #define F_ESIGN    2    /* set exponent's sign */
  15. #define F_INT    3    /* adjust integer part */
  16. #define F_FRAC    4    /* adjust fraction part */
  17. #define F_EXP    5    /* adjust exponent part */
  18. #define F_QUIT    6
  19.  
  20. #define NSTATE    8
  21. #define FS_INIT        0    /* initial state */
  22. #define FS_SIGNED    1    /* saw sign */
  23. #define FS_DIGS        2    /* saw digits, no . */
  24. #define FS_DOT        3    /* saw ., no digits */
  25. #define FS_DD        4    /* saw digits and . */
  26. #define FS_E        5    /* saw 'e' */
  27. #define FS_ESIGN    6    /* saw exp's sign */
  28. #define FS_EDIGS    7    /* saw exp's digits */
  29.  
  30. #define FC_DIG        0
  31. #define FC_DOT        1
  32. #define FC_E        2
  33. #define FC_SIGN        3
  34.  
  35. /* given transition,state do what action? */
  36. int fp_do[][NSTATE] = {
  37.     {F_INT,F_INT,F_INT,
  38.      F_FRAC,F_FRAC,
  39.      F_EXP,F_EXP,F_EXP},    /* see digit */
  40.     {F_NADA,F_NADA,F_NADA,
  41.      F_QUIT,F_QUIT,F_QUIT,F_QUIT,F_QUIT},    /* see '.' */
  42.     {F_QUIT,F_QUIT,
  43.      F_NADA,F_QUIT,F_NADA,
  44.      F_QUIT,F_QUIT,F_QUIT},    /* see e/E */
  45.     {F_SIGN,F_QUIT,F_QUIT,F_QUIT,F_QUIT,
  46.      F_ESIGN,F_QUIT,F_QUIT},    /* see sign */
  47. };
  48. /* given transition,state what is new state? */
  49. int fp_ns[][NSTATE] = {
  50.     {FS_DIGS,FS_DIGS,FS_DIGS,
  51.      FS_DD,FS_DD,
  52.      FS_EDIGS,FS_EDIGS,FS_EDIGS},    /* see digit */
  53.     {FS_DOT,FS_DOT,FS_DD,
  54.      },    /* see '.' */
  55.     {0,0,
  56.      FS_E,0,FS_E,
  57.     },    /* see e/E */
  58.     {FS_SIGNED,0,0,0,0,
  59.      FS_ESIGN,0,0},    /* see sign */
  60. };
  61. /* which states are valid terminators? */
  62. int fp_sval[NSTATE] = {
  63.     0,0,1,0,1,0,0,1
  64. };
  65. #endif
  66.  
  67. _scanf(ip, get, unget, fmt, args)
  68.     register unsigned char *ip;
  69.     int (*get)();
  70.     int (*unget)();
  71.     register unsigned char *fmt;
  72.     char **args;
  73.  
  74.     {
  75.     register long n;
  76.     register int c, width, lval, cnt = 0;
  77.     int store, neg, base, wide1, endnull, rngflag, c2;
  78.     register unsigned char *p;
  79.     unsigned char delim[128], digits[17], *q;
  80.     char *strchr(), *strcpy();
  81. #if FLOATS
  82.     long frac, expo;
  83.     int eneg, fraclen, fstate, trans;
  84.     double fx, fp_scan();
  85. #endif
  86.  
  87.     if (!*fmt)
  88.         return(0);
  89.  
  90.     c = (*get)(ip);
  91.     while(c > 0)
  92.         {
  93.         store = FALSE;
  94.         if (*fmt == '%')
  95.             {
  96.             n    = 0;
  97.             width    = -1;
  98.             wide1    = 1;
  99.             base    = 10;
  100.             lval    = FALSE;
  101.             store    = TRUE;
  102.             endnull    = TRUE;
  103.             neg    = -1;
  104.  
  105.             strcpy(delim,  "\011\012\013\014\015 ");
  106.             strcpy(digits, _numstr); /* "01234567890ABCDEF" */
  107.  
  108.             if (fmt[1] == '*')
  109.                 {
  110.                 endnull = store = FALSE;
  111.                 ++fmt;
  112.                 }
  113.  
  114.             while (isdigit(*++fmt))        /* width digit(s) */
  115.                 {
  116.                 if (width == -1)
  117.                     width = 0;
  118.                 wide1 = width = (width * 10) + (*fmt - '0');
  119.                 }
  120.             --fmt;
  121. fmtnxt:
  122.             ++fmt;
  123.             switch(tolower(*fmt))    /* tolower() is a MACRO! */
  124.                 {
  125.                 case '*':
  126.                     endnull = store = FALSE;
  127.                     goto fmtnxt;
  128.  
  129.                 case 'l':    /* long data */
  130.                     lval = TRUE;
  131. /* for compatability --> */    case 'h':    /* short data */
  132.                     goto fmtnxt;
  133.  
  134.                 case 'i':    /* any-base numeric */
  135.                     base = 0;
  136.                     goto numfmt;
  137.  
  138.                 case 'b':    /* unsigned binary */
  139.                     base = 2;
  140.                     goto numfmt;
  141.  
  142.                 case 'o':    /* unsigned octal */
  143.                     base = 8;
  144.                     goto numfmt;
  145.  
  146.                 case 'x':    /* unsigned hexadecimal */
  147.                     base = 16;
  148.                     goto numfmt;
  149.  
  150.                 case 'd':    /* SIGNED decimal */
  151.                     neg = FALSE;
  152.                     /* FALL-THRU */
  153.  
  154.                 case 'u':    /* unsigned decimal */
  155. numfmt:                    skip();
  156.  
  157.                     if (isupper(*fmt))
  158.                         lval = TRUE;
  159.  
  160.                     if (!base)
  161.                         {
  162.                         base = 10;
  163.                         neg = FALSE;
  164.                         if (c == '%')
  165.                             {
  166.                             base = 2;
  167.                             goto skip1;
  168.                             }
  169.                         else if (c == '0')
  170.                             {
  171.                             c = (*get)(ip);
  172.                             if (c < 1)
  173.                                 goto savnum;
  174.                             if ((c != 'x')
  175.                              && (c != 'X'))
  176.                                 {
  177.                                 base = 8;
  178.                                 digits[8]= '\0';
  179.                                 goto zeroin;
  180.                                 }
  181.                             base = 16;
  182.                             goto skip1;
  183.                             }
  184.                         }
  185.  
  186.                     if ((neg == FALSE) && (base == 10)
  187.                      && ((neg = (c == '-')) || (c == '+')))
  188.                         {
  189. skip1:
  190.                         c = (*get)(ip);
  191.                         if (c < 1)
  192.                             goto done;
  193.                         }
  194.  
  195.                     digits[base] = '\0';
  196.                     p = ((unsigned char *)
  197.                         strchr(digits,toupper(c)));
  198.  
  199.                     if ((!c || !p) && width)
  200.                         goto done;
  201.  
  202.                     while (p && width-- && c)
  203.                         {
  204.                         n = (n * base) + (p - digits);
  205.                         c = (*get)(ip);
  206. zeroin:
  207.                         p = ((unsigned char *)
  208.                         strchr(digits,toupper(c)));
  209.                         }
  210. savnum:
  211.                     if (store)
  212.                         {
  213.                         p = ((unsigned char *) *args);
  214.                         if (neg == TRUE)
  215.                             n = -n;
  216.                         if (lval)
  217.                             *((long*) p) = n;
  218.                         else
  219.                             *((int *) p) = n;
  220.                         ++cnt;
  221.                         }
  222.                     break;
  223.  
  224. #if FLOATS
  225.                 case 'e':    /* float */
  226.                 case 'f':
  227.                 case 'g':
  228.                     skip();
  229.  
  230.                     if (isupper(*fmt))
  231.                         lval = TRUE;
  232.  
  233.                     fstate = FS_INIT;
  234.                     neg = FALSE;  eneg = FALSE;
  235.                     n = 0;  frac = 0;  expo = 0;
  236.                     fraclen = 0;
  237.  
  238.                     while (c && width--) {
  239.                         if (c >= '0' && c <= '9')
  240.                             trans = FC_DIG;
  241.                         else if (c == '.')
  242.                             trans = FC_DOT;
  243.                         else if (c == '+' || c == '-')
  244.                             trans = FC_SIGN;
  245.                         else if (tolower(c) == 'e')
  246.                             trans = FC_E;
  247.                         else
  248.                             goto fdone;
  249.  
  250.                         switch (fp_do[trans][fstate]) {
  251.                         case F_SIGN:
  252.                             neg = (c == '-');
  253.                             break;
  254.                         case F_ESIGN:
  255.                             eneg = (c == '-');
  256.                             break;
  257.                         case F_INT:
  258.                             n = 10*n + (c - '0');
  259.                             break;
  260.                         case F_FRAC:
  261.                            frac = 10*frac + (c - '0');
  262.                             fraclen++;
  263.                             break;
  264.                         case F_EXP:
  265.                            expo = 10*expo + (c - '0');
  266.                             break;
  267.                         case F_QUIT:
  268.                             goto fdone;
  269.                         }
  270.                         fstate = fp_ns[trans][fstate];
  271.                         c = (*get)(ip);
  272.                     }
  273.  
  274. fdone:
  275.                     if (!fp_sval[fstate])
  276.                         goto done;
  277.                     if (store) {
  278.                         fx = fp_scan(neg, eneg,
  279.                             n, frac, expo, fraclen);
  280.                         p = (unsigned char *) *args;
  281.                         if (lval)
  282.                             *((double *) p) = fx;
  283.                         else
  284.                             *((float *) p) = fx;
  285.                         ++cnt;
  286.                     }
  287.                     break;
  288. #endif
  289.  
  290.                 case 'c':    /* character data */
  291.                     width = wide1;
  292.                     endnull    = FALSE;
  293.                     delim[0] = '\0';
  294.                     goto strproc;
  295.  
  296.                 case '[':    /* string w/ delimiter set */
  297.  
  298.                     /* get delimiters */
  299.                     p = delim;
  300.  
  301.                     if (*++fmt == '^')
  302.                         fmt++;
  303.                     else
  304.                         lval = TRUE;
  305.  
  306.                     rngflag = 2;
  307.                     if ((*fmt == ']') || (*fmt == '-'))
  308.                         {
  309.                         *p++ = *fmt++;
  310.                         rngflag = FALSE;
  311.                         }
  312.  
  313.                     while (*fmt != ']')
  314.                         {
  315.                         if (*fmt == '\0')
  316.                             goto done;
  317.                         switch (rngflag)
  318.                             {
  319.                             case TRUE:
  320.                             c2 = *(p-2);
  321.                             if (c2 <= *fmt)
  322.                                 {
  323.                                 p -= 2;
  324.                                 while (c2 < *fmt)
  325.                                     *p++ = c2++;
  326.                                 rngflag = 2;
  327.                                 break;
  328.                                 }
  329.                             /* fall thru intentional */
  330.  
  331.                             case FALSE:
  332.                             rngflag = (*fmt == '-');
  333.                             break;
  334.  
  335.                             case 2:
  336.                             rngflag = FALSE;
  337.                             }
  338.  
  339.                         *p++ = *fmt++;
  340.                         }
  341.  
  342.                     *p = '\0';
  343.                     goto strproc;
  344.  
  345.                 case 's':    /* string data */
  346.                     skip();
  347. strproc:
  348.                     /* process string */
  349.                     p = ((unsigned char *) *args);
  350.  
  351.                     /* if the 1st char fails, match fails */
  352.                     if (width)
  353.                         {
  354.                         q = ((unsigned char *)
  355.                             strchr(delim, c));
  356.                         if((c < 1)
  357.                         || (lval ? !q : (int) q))
  358.                             {
  359.                             if (endnull)
  360.                                 *p = '\0';
  361.                             goto done;
  362.                             }
  363.                         }
  364.  
  365.                     for (;;) /* FOREVER */
  366.                         {
  367.                         if (store)
  368.                             *p++ = c;
  369.                         if (((c = (*get)(ip)) < 1) ||
  370.                             (--width == 0))
  371.                             break;
  372.  
  373.                         q = ((unsigned char *)
  374.                             strchr(delim, c));
  375.                         if (lval ? !q : (int) q)
  376.                             break;
  377.                         }
  378.  
  379.                     if (store)
  380.                         {
  381.                         if (endnull)
  382.                             *p = '\0';
  383.                         ++cnt;
  384.                         }
  385.                     break;
  386.  
  387.                 case '\0':    /* early EOS */
  388.                     --fmt;
  389.                     /* FALL THRU */
  390.  
  391.                 default:
  392.                     goto cmatch;
  393.                 }
  394.             }
  395.         else if (isspace(*fmt))        /* skip whitespace */
  396.             {
  397.             skip();
  398.             }
  399.         else 
  400.             {            /* normal match char */
  401. cmatch:
  402.             if (c != *fmt) 
  403.                 break;
  404.             c = (*get)(ip);
  405.             }
  406.  
  407.         if (store)
  408.             args++;
  409.  
  410.         if (!*++fmt)
  411.             break;
  412.         }
  413.  
  414. done:                        /* end of scan */
  415.     if ((c < 0) && (cnt == 0))
  416.         return(EOF);
  417.  
  418.     (*unget)(c, ip);
  419.     return(cnt);
  420.     }
  421.